#ifndef _ASM_HOOK_H
#define _ASM_HOOK_H



#include "AsmCall.h"




class AsmHook;

//eax, ecx, edx, ebx, esp, ebp, esi, edi
#pragma pack(push,1)
struct _stackReg
{
	_regVal _eax;
	_regVal _ecx;
	_regVal _edx;
	_regVal _ebx;
	_regVal _esp;
	_regVal _ebp;
	_regVal _esi;
	_regVal _edi;
};
const int MaxStoredCode = 10;						// maximum number of instruction bytes that can be copied out

struct HookDispatcher
	{
#if defined (_DEBUG) 
		unsigned char int3;
#endif
		unsigned short addEsp;						// clobber the return address;
		unsigned char  four;						// the 4 bytes of return address
		unsigned char  pusha;						// save the original registers;
		unsigned char  movecx;						// move into the ecx register
		unsigned long  thisptr;						// the this pointer of the calling object
		unsigned long  leaebx;						// lea esp-32
		unsigned char  pushebx;						// push the stack location in ebx
		unsigned char  moveax;						// mov the method address into eax
		unsigned long  address;						// method address;
		unsigned short calleax;						// call the supplied second stage dispatcher
		unsigned char  popa;						// restore the registers;
		unsigned char  storedCode[MaxStoredCode];	// do the original instructions
		unsigned char  pushadd;						// restore the original address;
		unsigned long  retaddr;
		unsigned char  ret;
		void init(unsigned long hookLoc, unsigned char takeoutSize,AsmHook *target);
	};
#pragma pack(pop)

class AsmHook
{

public:
	AsmHook(unsigned long address,			// address of the instructions we want to replace
			unsigned char takeout_size = 5);// size of the instruction block removed 5 == minimum code for a relative call instruction
	virtual void hookfunc(_stackReg *regs) {}
	
private:
	unsigned long mAddress;
	unsigned char mTakeoutSize;
	void dispatch(_stackReg *regs)
	{
		// call the final method - awkward, but better than sifting through _vftables in assembly 
		hookfunc(regs); 		
	}
	HookDispatcher *mDispatcher;
};




#endif //_ASM_CALL_H